// 没有返回值，默认返回空元组
fn div(a: i32, b: i32) {
    println!("c = {}", (a as f64) / (b as f64));
}

// 有返回值（值类型，copy value）
fn add(a: i32, b: i32) -> i32 {
    // 1. 返回值类型，用->表示
    // 2. 不带分号，当作返回值自动返回
    a + b
}

// 有返回值（值类型，non-copy value）
fn tip(a: i32) -> String {
    // 返回 non-copy 值类型，会自动分配在堆上，在性能表现上差一些
    if a > 0 {
        "hello rust".to_owned()
    } else {
        String::from("hello world")
    }
}

// 有返回值（引用类型）
fn emoji(a: i32) -> &'static str {
    if a > 0 {
        "😊"
    } else {
        "😢"
    }
}

// 参数（值类型，形参可变）
fn mul(mut a: i32) {
    // 在函数体中，使用mut关键字，表示可变变量
    a = a * 10;
    println!("a = {}", a);
}

// 参数（引用类型，可变引用）
fn sub(a: &mut i32) {
    // 传入可变引用，需要解引用
    *a = *a - 1;
    println!("a = {}", a);
}

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

// 参数（值类型，non-copy）
fn get_point(p: Point) {
    println!("p = {:?}", p);
}

// 参数（引用类型，不可变引用）
fn print_point(p: &Point) {
    println!("p = {:?}", p);
}

// 参数（引用类型，可变引用）
fn modify_point(p: &mut Point) {
    // 通过.自动解引用语法糖，p.x = (*p).x（这是Rust内部帮忙处理的自动解引用，省去了显示解引用）
    p.x = 10;
    p.y = 20;
    println!("p = {:?}", p);
}

fn main() {
    /*-----------------参数----------------- */
    // 参数（copy）
    let a = 1;
    println!("a = {}", a);
    mul(a);
    println!("a = {}", a);

    // 参数（non-copy）
    let p = Point { x: 1, y: 2 };
    println!("p = {:?}", p);
    get_point(p);
    // 下面不能继续使用原因，1. 参数是值类型，2. 参数是non-copy类型
    // println!("p = {:?}", p);

    // 参数（borrow）
    let mut a = 1;
    println!("a = {}", a);
    sub(&mut a);
    // 下面能继续使用有两个原因，1. 参数是可变引用，2. 参数是基础类型，分配在栈上
    println!("a = {}", a);

    // 参数（borrow）
    let p = Point { x: 1, y: 2 };
    println!("p = {:?}", p);
    print_point(&p);
    // 下面能继续使用原因，1. 参数是引用
    println!("p = {:?}", p);

    // 参数（borrow）
    let mut p = Point { x: 1, y: 2 };
    println!("p = {:?}", p);
    modify_point(&mut p);
    // 下面能继续使用原因，1. 参数是可变引用
    println!("p = {:?}", p);

    println!("----------------------------------");

    /*-----------------返回值----------------- */
    // 没有返回值
    let a = 1;
    let b = 2;
    println!("a, b = {}, {}", a, b);
    div(a, b);

    // 有返回值（返回值，copy）
    let a = 1;
    let b = 2;
    println!("a, b = {}, {}", a, b);
    // 这里a和b，属于基础类型，分配在栈上，所有在传参时自动复制
    let c = add(a, b);
    println!("a, b, c = {}, {}, {}", a, b, c);

    // 有返回值（返回值，non-copy）
    let a = 1;
    println!("a = {}", a);
    let b = tip(a);
    println!("a = {}, b = {}", a, b);

    // 有返回值（返回值，borrow）
    let a = 0;
    println!("a = {}", a);
    let b = emoji(a);
    println!("a = {}, b = {}", a, b);
}
